
export default class {
    constructor (variants) {
        this.attributes = {};
        this.records = {};
        this._keys = [];
        this._cache_related = {};

        // 当前选择的sku属性，以及选择sku属性计算后的结果集
        this._current_choose = {};

        let _prime_generator = this._prime_number(),
            index = _prime_generator.next();

        for (const variant of variants) {
            if (this._keys.length === 0) {
                this._keys = Object.keys(variant.variant);

                if (this._keys.length === 0) return;

                this._init_attributes();
            }

            for (const value in variant.variant) {
                if (!this.attributes[value].values[variant.variant[value]]) {
                    this._init_attributes_values(value, variant.variant[value]);
                }

                if (variant.stock > 0){
                    this._update_value_related(value, variant.variant[value], index.value);
                }
            }

            // 只有存在库存的、也就是可以被sku选择到的才记录下来
            if (variant.stock > 0) {
                const variant_key = this._gerenate_variant_key(variant.variant);

                delete variant.variant;

                this.records[variant_key] = variant;
            }

            index = _prime_generator.next();
        }

        this._refresh_active();
    }

    get_record() {
        return this.records[this._gerenate_object_attribute_key(this._current_choose)];
    }

    get_unchoosed_key() {
        return this._keys.filter((key) => !Boolean(this._current_choose[key]));
    }

    get_current_choose() {
        return Object.assign({}, this._current_choose);
    }

    // 计算两个数组的交集
    _compute_intersection(left, right) {
        if (left[left.length - 1] < right[0] || left[0] > right[right.length - 1]) {
            return []
        }

        const [min_array, max_array] =
            (left.length < right.length)? [left, right]: [right, left];

        const multiplied = max_array.reduce((multi, value) => multi * value, 1);
        return min_array.filter((number) => Boolean(multiplied % number === 0));
    }

    _refresh_active (choosed, choosed_value={}) {
        for (const attribute in this.attributes) {
            if (!choosed_value.choosed || attribute != choosed) {
                const temp_related_ids = this._get_temp_related(attribute);
                for (const key in this.attributes[attribute].values) {
                    const value = this.attributes[attribute].values[key];
                    if (temp_related_ids.length === 0 && value.related_ids.length != 0) {
                        value.active = true;
                    } else {
                        value.active = this._compute_intersection(
                            temp_related_ids, value.related_ids).length > 0;
                    }
                }
            }
        }
    }

    select_value (attribute, value) {
        this._update_current_choose(attribute, value);
        this._refresh_active(attribute, value);

        if (this._keys.filter((key) => Boolean(this._current_choose[key])).length
            === this._keys.length) {
            return this.get_record();
        }
    }

    _get_temp_related(attribute) {
        const temp_choose = Object.assign({}, this._current_choose)
        delete temp_choose[attribute]

        return this._get_current_related_ids(temp_choose, {})
    }

    _get_current_related_ids(left, right) {
        const left_related = this._get_related_by_cache(left);
        const right_related = this._get_related_by_cache(right);

        if (left_related.length === 0 || right_related.length === 0) {
            return left_related.length === 0? right_related : left_related;
        }

        return this._compute_intersection(left_related, right_related)
    }


    _get_related_by_cache(attribute) {
        const key = this._gerenate_object_attribute_key(attribute);
        if (!key) {
            return [];
        }

        if (this._cache_related[key]) {
            return this._cache_related[key];
        }

        const _temp_keys = this._keys.filter((key) => Boolean(attribute[key]));
        if (_temp_keys.length <= 0) return [];
        if (_temp_keys.length === 1) {
            this._cache_related[key] = attribute[_temp_keys[0]].related_ids;
        } else {
            const _temp_attribute = Object.assign({}, attribute);
            delete _temp_attribute[_temp_keys[0]];

            this._cache_related[key] = this._get_current_related_ids(
                _temp_attribute, {[_temp_keys[0]]: attribute[_temp_keys[0]]});
        }

        return this._cache_related[key];
    }

    _update_current_choose(attribute, value) {
        value.choosed = !value.choosed;

        if (this._current_choose[attribute]) {
            if (this._current_choose[attribute].name === value.name) {
                delete this._current_choose[attribute];
                return;
            }

            this._current_choose[attribute].choosed = false;
            delete this._current_choose[attribute];
        }

        this._current_choose[attribute] = value;
    }

    // 质数生成器
    *_prime_number () {
        const is_prime = (number) => {
            for (let i = 3; i <= Math.sqrt(number); i += 2) {
                if (number % i === 0) {
                    return false
                }
            }

            return true
        }

        yield 2

        let index = 3;
        while (true) {
            if (is_prime(index)) yield index;
            index += 2
        }
    }

    _update_value_related(attribute, value, index) {
        this.attributes[attribute].values[value].related_ids.push(index);
    }

    _init_attributes_values(attribute, value) {
        this.attributes[attribute].values[value] = {
            name: value,
            choosed: false,
            active: true,
            related_ids: []
        }
    }

    _init_attributes() {
        for (const key of this._keys) {
            this.attributes[key] = {
                name: key,
                values: {}
            }
        }
    }

    _gerenate_object_attribute_key(attribute) {
        const res = this._keys
                 .filter((key) => Boolean(attribute[key]))
                 .map((key) => this._compute_key(key, attribute[key].name))

        return res.join(';');
    }

    _gerenate_variant_key(variant) {
        const res = this._keys
                 .filter((key) => Boolean(variant[key]))
                 .map((key) => this._compute_key(key, variant[key]));

        return res.join(';');
    }

    // 冒号可能会重复的问题
    _compute_key(key, value) {
        return `${key}:${value}`;
    }
}
